package com.engine.wei.base.mvp.presenter;

import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;

import com.engine.wei.base.mvp.contract.BaseContract;
import com.engine.wei.base.mvp.model.BaseModel;
import com.engine.wei.base.utils.log.LogUtils;
import com.engine.wei.base.utils.Preconditions;
import com.engine.wei.base.utils.rxjava.RxUtils;

import java.lang.ref.WeakReference;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Action;
import io.reactivex.rxjava3.schedulers.Schedulers;

/**
 * 作者:赵若位
 * 时间:2021/8/25 17:48
 * 功能:
 */
public class BasePresenter<V extends BaseContract.IView, M extends BaseModel> implements IPresenter<V> {

    private V mView;
    private M mModel;
    private CompositeDisposable mDisposable;
    private WeakReference<V> mWeakReference;

    public BasePresenter() {

    }

    @Override
    public void onAttach(@NonNull V view) {
        //TODO 这里tmd的测试一下当null == view时候,view.getclass.getSimpleName是否能获取到
        this.mView = Preconditions.checkNotNull(view, "The MVP's View of %s is empty!", view.getClass().getName());
        mWeakReference = new WeakReference<>(mView);
        if (null != view && null != view.getDependencies()) {
            view.getDependencies().getLifecycle().addObserver(this);
        }
    }

    protected V getView() {
        return null == mWeakReference || null == mWeakReference.get() ? null : mWeakReference.get();
    }

    protected final void addDisposable(@NonNull Disposable disposable) {
        if (null == mDisposable) {
            mDisposable = new CompositeDisposable();
        }
        if (null != disposable) {
            mDisposable.add(disposable);
        }
    }


    /**
     * 对{@link #single(Single, boolean)}和{@link #single(Single)}进行封装
     * 主要是对线程切换，内存泄露以及进度条的封装
     */
    protected <T> Single<T> single(Single<T> single, boolean isLoading) {
        Preconditions.checkNotNull(single, "The Single of %s is empty!", getClass().getSimpleName());
        return single.subscribeOn(Schedulers.io())
                .doOnSubscribe(disposable -> {
                    if (null != disposable) {
                        addDisposable(disposable);
                    }
                })
                .compose(RxUtils.singleLoading(isLoading ? getView() : null))
                .compose(getView().bindRxLifecycle());
    }

    protected <T> Single<T> single(Single<T> single) {
        return single(single, true);
    }


    protected <T> Observable<T> observable(Observable<T> observable, boolean isLoading) {
        observable = Preconditions.checkNotNull(observable, "The Observable of %s is empty!",
                getClass().getSimpleName());
        return observable.subscribeOn(Schedulers.io())
                .doOnSubscribe(disposable -> {
                    if (null != disposable) {
                        addDisposable(disposable);
                    }
                })
                .compose(RxUtils.observableLoading(isLoading ? getView() : null))
                .unsubscribeOn(Schedulers.io())
                .compose(getView().bindRxLifecycle());
    }

    protected <T> Observable<T> observable(Observable<T> observable) {
        return observable(observable, true);
    }

    /**
     * 注意, 如果在这里调用了 {@link #onDestroy(LifecycleOwner)} 方法, 会出现某些地方引用 {@code mModel} 或 {@code mRootView} 为 null 的情况
     * 比如在 {@link com.trello.rxlifecycle4.RxLifecycle} 终止 {@link io.reactivex.rxjava3.core.Observable} 时,
     * 在 {@link io.reactivex.rxjava3.core.Observable#doFinally(Action)} 中却引用了 {@code mRootView} 做一些释放资源的操作, 此时会空指针
     * 或者如果你声明了多个 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 时在其他 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
     * 中引用了 {@code mModel} 或 {@code mRootView} 也可能会出现此情况
     */
    @Override
    public void onDestroy(LifecycleOwner owner) {
        LogUtils.i("The MVP'Presenter of %s is unbinding", getClass().getSimpleName());
        if (null != mWeakReference) {
            mWeakReference.clear();
            mWeakReference = null;
        }
        if (null != mDisposable) {
            mDisposable.dispose();
            mDisposable.clear();
            mDisposable = null;
        }
        mView = null;
        if (null != mModel) {
            mModel.onDestroy();
        }
        if (null != owner) {
            owner.getLifecycle().removeObserver(this);
        }
    }

}
